package ldh.im.fxgui.controller;

import com.google.common.eventbus.Subscribe;
import javafx.animation.TranslateTransition;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.input.*;
import javafx.scene.layout.*;
import javafx.util.Duration;
import ldh.im.ImConfig;
import ldh.im.fxbase.data.event.EventBusFactory;
import ldh.im.fxbase.data.event.GroupNameChange;
import ldh.im.fxbase.data.pojo.*;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.component.message.*;
import ldh.im.fxbase.dao.ImMessageDao;
import ldh.im.fxgui.component.message.bo.WrapImMessage;
import ldh.im.fxgui.controller.sub.SessionGroupSettingController;
import ldh.im.fxgui.controller.sub.SessionUserSettingController;
import ldh.im.fxgui.controller.sub.MessageEditorController;
import ldh.im.fxgui.controller.sub.MessageSelectController;
import ldh.im.fxgui.pojo.MessageRefresh;
import ldh.im.fxgui.service.MessageReadService;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.util.ConfigUtil;
import ldh.im.util.DateUtil;
import ldh.rpc.cache.CacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 消息发送面板处理器
 */
public class MessageSendController extends BaseController implements Initializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(MessageSendController.class);

    @FXML private MessageEditorController messageEditorController;   //  消息编辑框组件
    @FXML private MessageSelectController messageSelectController;   // 消息选择框

    @FXML private StackPane root;
    @FXML private Pane messageListPane;     // 消息展示列表的容器
    @FXML private Label titleLabel;         // 标题

    @FXML private Pane settingPane;         // 会议设置面板

    private Node messageListView;           // 消息展示列表

    private MessageSessionController messageSessionController;       // 会话组件
    private MessageListViewHandler messageListViewHandler;           // 消息展示处理抽象接口

    // 会话控制面板显示可见或不可见
    private BooleanProperty settingPaneShowProperty = new SimpleBooleanProperty(false);
    private ImSession currentSession;       // 当前会话

    private AtomicBoolean isLoading = new AtomicBoolean(false); // 是否数据正在加载中

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        messageListViewHandler = new MessageVirtualFlowView(messageEditorController, root);
//        messageListViewHandler = new MessageListView();

        messageListView = messageListViewHandler.createMessagePaneNode();
        messageListView.setMouseTransparent(false);

        messageListPane.getChildren().add(0, messageListView);

        // 消息面板和消息选择面板
        messageEditorController.setDialogRoot(root);
        messageEditorController.setMessageSendController(this);
        messageEditorController.setSettingPaneShowProperty(settingPaneShowProperty);

        messageSelectController.setMessageListViewHandler(messageListViewHandler);
        messageSelectController.hide();

        // 会议控制面板
        double controlPaneTranslateX = 260 + 10;
        messageListPane.widthProperty().addListener(e->{
            settingPane.setTranslateX(controlPaneTranslateX);
        });
        settingPane.setTranslateX(controlPaneTranslateX);

        bindEvent();
    }

    public void setMessageSessionController(MessageSessionController messageSessionController) {
        this.messageSessionController = messageSessionController;
        messageEditorController.setDialogRoot(StageUtil.getRoot());
        messageListViewHandler.setDialogRoot(StageUtil.getRoot());
    }

    public void requestFocus() {
        messageEditorController.requestFocus();
    }

    public void unRegisterEvent() {
        EventBusFactory.getInstance().unregister(messageListViewHandler);
        EventBusFactory.getInstance().unregister(this);
    }

    public void setImSession(ImSession imSession) {
        this.currentSession = imSession;
        this.messageEditorController.setImSession(imSession);
        titleLabel.setText(imSession.getMessageSessionName());
        settingPane.getChildren().clear();
        LOGGER.info("show user message !!!!!!!!!!!!!!!!, {}", imSession.getMessageSessionName());
        this.messageListViewHandler.setImSession(imSession);
        UiUtil.setSendMessageHandler(this.messageListViewHandler);

        registerEvent();
        messageListViewHandler.getItems().clear();
        loadData();
    }

    public void reloadSession(ImSession imSession) {
        if (messageSessionController != null) {
            messageSessionController.reloadMessageSession(imSession);
        }
    }

    public void upEvent() {
        if (messageSessionController != null) {
            messageSessionController.up();
        }
    }

    public void downEvent() {
        if (messageSessionController != null) {
            messageSessionController.down();
        }
    }

    public void showMessages(ImSession imSession, List<ImMessage> messages) {
        messageListViewHandler.addMessages(messages);
        messageSessionController.updateSession(imSession);
    }

    public void loadLastedMessage() {
        loadData();
    }

    @Subscribe
    public void groupNameChange(GroupNameChange groupNameChange) {
        if (!groupNameChange.getGroupId().equals(currentSession.getGroupCode())) return;
        FxThreadUtil.runLater(()->{
            titleLabel.setText(groupNameChange.getName());
        });
    }

    @FXML
    private void showSettingPane(MouseEvent mouseEvent) {
        settingPaneShowProperty.setValue(!settingPaneShowProperty.getValue());
        if (settingPane.getChildren().size() < 1) {
            if (currentSession.isP2p()) {
                String fxml = "/fxml/sub/SessionUserSettingPane.fxml";
                RegionUtil.FxmlBean<VBox, SessionUserSettingController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource(fxml));
                settingPane.getChildren().add(fxmlBean.getNode());
                fxmlBean.getController().setParams(currentSession, messageSessionController, settingPaneShowProperty);
                fxmlBean.getController().setDialogRoot(root);
            } else {
                String fxml = "/fxml/sub/SessionGroupSettingPane.fxml";
                RegionUtil.FxmlBean<VBox, SessionGroupSettingController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource(fxml));
                settingPane.getChildren().add(fxmlBean.getNode());
                fxmlBean.getController().setDialogRoot(root);
                fxmlBean.getController().setParams(currentSession, settingPaneShowProperty);
            }
        }
    }

    private void loadData() {
        ThreadPoolUtil.submit(()->{
            try {
                ImMessageDao imMessageDao = BeanFactory.getInstance().getBean(ImMessageDao.class);

                int size = ConfigUtil.getInt("message.init_size", 500);
                List<ImMessage> messages = null;

                if (messageListViewHandler.getItems().size() > 0) {
                    WrapImMessage wrapImMessage = messageListViewHandler.getItems().get(0);
                    ImMessage imMessage = wrapImMessage.getImMessage();
                    Date startDay = imMessage.getServerReceiveTime();
                    messages = imMessageDao.getNewMessagesBySessionId(currentSession.getId(), startDay, size);
                } else {
                    int messageShowDay = ConfigUtil.getInt("message.session.showDay", -14);
                    LocalDateTime startDay = LocalDateTime.now().plusDays(messageShowDay);
                    messages = imMessageDao.getBySessionIdAndDate(currentSession.getId(), DateUtil.toDate(startDay), size);
                }

                messages.forEach(m-> m.setImSession(currentSession));

                final List<ImMessage> finalMessages = messages;
                FxThreadUtil.runLater(()->{
                    UiUtil.setSendMessageHandler(messageListViewHandler);
                    messageListViewHandler.addMessages(finalMessages);
                });

                CacheService cacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getCacheService();
                String userId = (String) cacheService.getCache(ImConfig.LOGIN_USER_ID);

                MessageReadService.getInstance().asyHandleReadMessage(currentSession.getId(), userId, messages);
//                imSessionDao.cleanHotMessageNum(currentSession.getId());
//
//                ImCacheFactory.getInstance().cleanHotMessage(currentSession.getId());
//
//                EventBusFactory.getInstance().post(new HotMessage(ImCacheFactory.getInstance().getAllHotMessage()));
//                EventBusFactory.getInstance().post(new HotMessageTotal(ImCacheFactory.getInstance().getAllHotMessage()));
            } catch (Exception e) {
                LOGGER.error("加载消息失败", e);
            }
        });
    }

    private void registerEvent() {
        EventBusFactory.getInstance().register(messageListViewHandler);
        EventBusFactory.getInstance().register(this);
    }

    private void bindEvent() {
        messageListView.setOnMouseClicked(e->{
            settingPaneShowProperty.setValue(false);
        });

        messageListView.setOnKeyPressed(e->{
            if (e.getCode() == KeyCode.UP) {
                messageListView.requestFocus();
                messageListViewHandler.showUp();
            } else if (e.getCode() == KeyCode.DOWN) {
                messageListView.requestFocus();
                messageListViewHandler.showDown();
            }
        });

//        registerEvent();
        initScrollLoad();

        messageListViewHandler.messageSelectProperty().addListener(l->{
            if (messageListViewHandler.messageSelectProperty().getValue()) {
                messageSelectController.show();
                messageEditorController.hide();
            } else {
                messageSelectController.hide();
                messageEditorController.show();
            }
        });

        settingPaneShowProperty.addListener(l->{
            if (!settingPaneShowProperty.getValue()) {
                TranslateTransition translateTransition = new TranslateTransition(Duration.millis(600));
                translateTransition.setNode(settingPane);
                translateTransition.setFromX(0);
                translateTransition.setToX(300);
                translateTransition.play();
            } else {
                TranslateTransition translateTransition = new TranslateTransition(Duration.millis(600));
                translateTransition.setNode(settingPane);
                translateTransition.setFromX(300);
                translateTransition.setToX(0);
                translateTransition.play();
            }
        });
    }

    private void initScrollLoad() {
        if (!(messageListViewHandler instanceof BaseMessageListViewHandler)) {
            return;
        }
        BaseMessageListViewHandler baseSendMessageHandler = (BaseMessageListViewHandler) messageListViewHandler;
        baseSendMessageHandler.setRefreshCallback((messageSession)->{
            ThreadPoolUtil.submit(()->{
                 return ExceptionUtil.catchException(()->{
                    ImMessageDao imMessageDao = BeanFactory.getInstance().getBean(ImMessageDao.class);
                    List<ImMessage> messages = imMessageDao.getBySessionId(messageSession.getId(), ConfigUtil.getInt("message.init_size", 500));
                     if (messages != null) {
                         FxThreadUtil.runLater(()->{
                             messageListViewHandler.getItems().clear();
                             messageListViewHandler.addMessages(messages);
                         });
                     }
                    return messages;
                }, "刷新数据");
            });
            return null;
        });
        baseSendMessageHandler.setLoadFrontCallback((Void)->{
            if (isLoading.get()) return null;
            try {
                isLoading.set(true);
                ImMessage firstMessage = messageListViewHandler.getFirstMessage();
                Date serverReceiveDate = null;
                if (firstMessage != null) {
                    serverReceiveDate = firstMessage.getServerReceiveTime();
                }
                long sessionId = currentSession.getId();
                String userId = currentSession.getCurrentUserId();
                ImMessageDao imMessageDao = BeanFactory.getInstance().getBean(ImMessageDao.class);
                List<ImMessage> oldMessages = imMessageDao.getOldMessagesBySessionId(currentSession.getId(), serverReceiveDate, 100);
                MessageReadService.getInstance().asyHandleReadMessage(sessionId, userId, oldMessages);
                return oldMessages.stream().map(m->WrapImMessage.wrap(m)).toList();
            } catch (Exception e) {
                LOGGER.error("load old messages error", e);
            } finally {
                isLoading.set(false);
            }
            return null;

//            loadData(()->{
//                MessageRefresh messageRefresh = ExceptionUtil.catchException(()->{
//                    isLoading.set(true);
//                    ImMessage firstMessage = messageListViewHandler.getFirstMessage();
//                    Date serverReceiveDate = null;
//                    if (firstMessage != null) {
//                        serverReceiveDate = firstMessage.getServerReceiveTime();
//                    }
//                    List<ImMessage> oldMessages = imMessageDao.getOldMessagesBySessionId(currentSession.getId(), serverReceiveDate, 100);
//                    return oldMessages.stream().map(m->WrapImMessage.wrap(m)).toList();
//                }, "加载数据");
//                isLoading.set(false);
//                return messageRefresh;
//            }, true);
//            return null;
        });

        baseSendMessageHandler.setLoadLastCallback((Void)->{
            if (isLoading.get()) return null;
            try {
                isLoading.set(true);
                ImMessage lastedMessage = messageListViewHandler.getLastedMessage();
                Date serverReceiveDate = null;
                if (lastedMessage != null) {
                    serverReceiveDate = lastedMessage.getServerReceiveTime();
                }
                ImMessageDao imMessageDao = BeanFactory.getInstance().getBean(ImMessageDao.class);
                List<ImMessage> lastedMessages = imMessageDao.getNewMessagesBySessionId(currentSession.getId(), serverReceiveDate, 100);
                return lastedMessages.stream().map(m->WrapImMessage.wrap(m)).toList();
            } catch (Exception e) {
                LOGGER.error("load new message error", e);
            } finally {
                isLoading.set(false);
            }
            return null;
//            loadData(()->{
//                MessageRefresh messageRefresh = ExceptionUtil.catchException(()->{
//                    isLoading.set(true);
//                    ImMessage lastedMessage = messageListViewHandler.getLastedMessage();
//                    Date serverReceiveDate = null;
//                    if (lastedMessage != null) {
//                        serverReceiveDate = lastedMessage.getServerReceiveTime();
//                    }
//                    List<ImMessage> lastedMessages = imMessageDao.getNewMessagesBySessionId(currentSession.getId(), serverReceiveDate, 100);
//                    return new MessageRefresh(new ArrayList<>(), lastedMessages);
//                }, "加载数据");
//                isLoading.set(false);
//                return messageRefresh;
//            }, false);
//            return null;
        });
    }

    private void loadData(Supplier<MessageRefresh> supplier, boolean isFront) {
        ThreadPoolUtil.submit(()->{
            ExceptionUtil.catchException(()->{
                MessageRefresh messageRefresh = supplier.get();
                if (messageRefresh == null) return null;
                List<ImMessage> messages = messageRefresh.getMessageList();
                if (messages.size() < 1) return messages;
                for(ImMessage message : messages) {
                    message.setImSession(currentSession);
                }
                FxThreadUtil.runLater(()->{
                    Set<Long> messageIdSet = messageListViewHandler.getMessageIdSet();
                    List<ImMessage> filterMessages = messages.stream().filter(m->!messageIdSet.contains(m.getId())).collect(Collectors.toList());
                    if (isFront) {
                        messageListViewHandler.addFrontMessages(filterMessages);
                    } else {
                        messageListViewHandler.addLastedMessages(filterMessages);
                    }
                    for (ImMessage message : messageRefresh.getRefreshMessageList()) {
                        messageListViewHandler.update(message);
                    }
                });
                MessageReadService.getInstance().asyHandleReadMessage(currentSession.getId(), currentSession.getCurrentUserId(), messages);
                return messages;
            }, "加载数据");
        });
    }
}
